import fs from 'fs';
import path from 'path';
import { Logger } from '../utils/logger.js';
import { ProgressBar } from '../utils/progressBar.js';
import { glob } from 'glob';

/**
 * 批量文件传输类
 */
class BatchTransfer {
  constructor(sftpClient) {
    this.sftpClient = sftpClient;
  }

  /**
   * 批量上传文件
   * @param {Array|string} patterns - 文件模式数组或单个模式
   * @param {string} remoteDir - 远程目录
   * @param {Object} options - 选项
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadFiles(patterns, remoteDir, options = {}) {
    const {
      preserveStructure = true,
      maxConcurrent = 3,
      verifyIntegrity = false,
      integrityAlgorithm = 'md5',
      resume = false,
      filter = null,
      onProgress = null,
      onFileComplete = null
    } = options;

    try {
      // 获取匹配的文件列表
      const files = await this._getFileList(patterns, filter);
      
      if (files.length === 0) {
        Logger.warn('没有找到匹配的文件');
        return { success: true, uploaded: [], failed: [], skipped: [] };
      }

      Logger.info(`准备上传 ${files.length} 个文件到 ${remoteDir}`);

      // 确保远程目录存在
      await this.sftpClient.createRemoteDir(remoteDir);

      // 初始化结果对象
      const result = {
        success: true,
        uploaded: [],
        failed: [],
        skipped: [],
        total: files.length,
        totalBytes: 0,
        uploadedBytes: 0
      };

      // 计算总字节数
      for (const file of files) {
        try {
          const stats = fs.statSync(file);
          result.totalBytes += stats.size;
        } catch (error) {
          Logger.warn(`无法获取文件大小: ${file}`);
        }
      }

      // 创建总体进度条
      const progressBar = new ProgressBar(result.totalBytes, '批量上传');

      // 分批处理文件
      const chunks = this._chunkArray(files, maxConcurrent);
      
      for (let i = 0; i < chunks.length; i++) {
        const chunk = chunks[i];
        const promises = chunk.map(file => this._uploadSingleFile(
          file, 
          remoteDir, 
          preserveStructure, 
          verifyIntegrity, 
          integrityAlgorithm, 
          resume,
          progressBar,
          result,
          onFileComplete
        ));
        
        await Promise.allSettled(promises);
        
        // 调用进度回调
        if (onProgress) {
          onProgress({
            completed: result.uploaded.length + result.failed.length + result.skipped.length,
            total: result.total,
            uploadedBytes: result.uploadedBytes,
            totalBytes: result.totalBytes
          });
        }
      }

      // 完成进度条
      progressBar.complete();

      // 输出结果
      if (result.failed.length === 0) {
        Logger.success(`批量上传完成: ${result.uploaded.length} 成功`);
      } else {
        Logger.warn(`批量上传完成: ${result.uploaded.length} 成功, ${result.failed.length} 失败`);
        
        // 记录失败的文件
        Logger.error('以下文件上传失败:');
        result.failed.forEach(item => Logger.error(`- ${item.file}: ${item.error}`));
      }

      return result;
    } catch (error) {
      Logger.error(`批量上传出错: ${error.message}`);
      return { success: false, error: error.message };
    }
  }

  /**
   * 批量下载文件
   * @param {string|array} patterns - 远程文件模式或模式数组
   * @param {string} localDir - 本地目录
   * @param {object} options - 选项
   * @returns {Promise<object>} 下载结果
   */
  async downloadFiles(patterns, localDir, options = {}) {
    const {
      maxConcurrent = 3,
      preserveStructure = true,
      verifyIntegrity = false,
      integrityAlgorithm = 'md5',
      resume = true,
      filter = null,
      onProgress = null,
      onFileComplete = null
    } = options;

    try {
      // 获取匹配的远程文件列表
      const files = await this._getRemoteFileList(patterns, filter);
      
      if (files.length === 0) {
        Logger.warn('没有找到匹配的远程文件');
        return { success: true, downloaded: [], failed: [], skipped: [] };
      }

      Logger.info(`准备下载 ${files.length} 个文件到 ${localDir}`);

      // 确保本地目录存在
      if (!fs.existsSync(localDir)) {
        fs.mkdirSync(localDir, { recursive: true });
      }

      // 初始化结果对象
      const result = {
        success: true,
        downloaded: [],
        failed: [],
        skipped: [],
        total: files.length,
        totalBytes: 0,
        downloadedBytes: 0
      };

      // 计算总字节数
      for (const file of files) {
        try {
          const stats = await this.sftpClient.getFileInfo(file);
          result.totalBytes += stats.size;
        } catch (error) {
          Logger.warn(`无法获取远程文件大小: ${file}`);
        }
      }

      // 创建总体进度条
      const progressBar = new ProgressBar(result.totalBytes, '批量下载');

      // 分批处理文件
      const chunks = this._chunkArray(files, maxConcurrent);
      
      for (let i = 0; i < chunks.length; i++) {
        const chunk = chunks[i];
        const promises = chunk.map(file => this._downloadSingleFile(
          file, 
          localDir, 
          preserveStructure, 
          verifyIntegrity, 
          integrityAlgorithm, 
          resume,
          progressBar,
          result,
          onFileComplete
        ));
        
        await Promise.allSettled(promises);
        
        // 调用进度回调
        if (onProgress) {
          onProgress({
            completed: result.downloaded.length + result.failed.length + result.skipped.length,
            total: result.total,
            downloadedBytes: result.downloadedBytes,
            totalBytes: result.totalBytes
          });
        }
      }

      // 完成进度条
      progressBar.complete();

      // 输出结果
      if (result.failed.length === 0) {
        Logger.success(`批量下载完成: ${result.downloaded.length} 成功`);
      } else {
        Logger.warn(`批量下载完成: ${result.downloaded.length} 成功, ${result.failed.length} 失败`);
        
        // 记录失败的文件
        Logger.error('以下文件下载失败:');
        result.failed.forEach(item => Logger.error(`- ${item.file}: ${item.error}`));
      }

      return result;
    } catch (error) {
      Logger.error(`批量下载出错: ${error.message}`);
      return { success: false, error: error.message };
    }
  }

  /**
   * 获取本地文件列表
   * @param {Array|string} patterns - 文件模式
   * @param {Function|null} filter - 过滤函数
   * @returns {Promise<Array>} - 文件列表
   * @private
   */
  async _getFileList(patterns, filter) {
    const patternArray = Array.isArray(patterns) ? patterns : [patterns];
    let files = [];
    
    for (const pattern of patternArray) {
      const matchedFiles = await glob(pattern, { 
        nonull: false,
        nodir: true  // 不包含目录
      });
      files = files.concat(matchedFiles);
    }
    
    // 去重
    files = [...new Set(files)];
    
    // 应用过滤器
    if (filter && typeof filter === 'function') {
      files = files.filter(filter);
    }
    
    return files;
  }

  /**
   * 获取远程文件列表
   * @param {string|array} patterns - 远程文件模式
   * @param {Function|null} filter - 过滤函数
   * @returns {Promise<Array>} - 文件列表
   * @private
   */
  async _getRemoteFileList(patterns, filter) {
    const patternArray = Array.isArray(patterns) ? patterns : [patterns];
    let allFiles = [];
    
    for (const pattern of patternArray) {
      try {
        // 获取目录和文件模式
        const { dir, base } = path.parse(pattern);
        const remoteDir = dir || '.';
        
        // 列出远程目录内容
        const files = await this.sftpClient.listFiles(remoteDir);
        
        // 使用 glob 模式匹配文件
        const globPattern = new RegExp(base.replace(/\*/g, '.*').replace(/\?/g, '.'));
        const matchedFiles = files
          .filter(file => file.type === '-') // 只包含文件，不包含目录
          .filter(file => globPattern.test(file.name))
          .map(file => path.posix.join(remoteDir, file.name));
          
        allFiles = allFiles.concat(matchedFiles);
      } catch (error) {
        Logger.warn(`无法获取远程文件列表: ${pattern} - ${error.message}`);
      }
    }
    
    // 去重
    allFiles = [...new Set(allFiles)];
    
    // 应用过滤器
    if (filter && typeof filter === 'function') {
      allFiles = allFiles.filter(filter);
    }
    
    return allFiles;
  }

  /**
   * 上传单个文件
   * @param {string} localFile - 本地文件路径
   * @param {string} remoteDir - 远程目录
   * @param {boolean} preserveStructure - 是否保持目录结构
   * @param {boolean} verifyIntegrity - 是否验证完整性
   * @param {string} integrityAlgorithm - 完整性算法
   * @param {boolean} resume - 是否断点续传
   * @param {ProgressBar} progressBar - 进度条
   * @param {Object} result - 结果对象
   * @param {Function} onFileComplete - 文件完成回调
   * @returns {Promise<void>}
   * @private
   */
  async _uploadSingleFile(
    localFile, 
    remoteDir, 
    preserveStructure, 
    verifyIntegrity, 
    integrityAlgorithm, 
    resume,
    progressBar,
    result,
    onFileComplete
  ) {
    try {
      // 计算远程文件路径
      let remoteFile;
      if (preserveStructure) {
        // 保持相对路径结构
        const relativePath = path.relative(process.cwd(), localFile);
        remoteFile = path.posix.join(remoteDir, relativePath.replace(/\\/g, '/'));
        
        // 确保远程目录存在
        const remoteFileDir = path.posix.dirname(remoteFile);
        if (remoteFileDir !== remoteDir) {
          await this.sftpClient.createRemoteDir(remoteFileDir);
        }
      } else {
        // 只使用文件名
        const fileName = path.basename(localFile);
        remoteFile = path.posix.join(remoteDir, fileName);
      }

      // 获取文件大小
      const stats = fs.statSync(localFile);
      const fileSize = stats.size;

      // 上传文件
      await this.sftpClient.uploadFile(localFile, remoteFile, {
        verifyIntegrity,
        integrityAlgorithm,
        resume
      });

      // 更新结果
      result.uploaded.push({
        local: localFile,
        remote: remoteFile,
        size: fileSize
      });
      
      result.uploadedBytes += fileSize;

      // 更新进度条
      progressBar.update(result.uploadedBytes);

      // 调用文件完成回调
      if (onFileComplete) {
        onFileComplete({
          file: localFile,
          status: 'uploaded',
          size: fileSize
        });
      }
    } catch (error) {
      // 更新失败结果
      result.failed.push({
        file: localFile,
        error: error.message
      });
      
      Logger.error(`上传文件失败: ${localFile} - ${error.message}`);
    }
  }

  /**
   * 下载单个文件
   * @param {string} remoteFile - 远程文件路径
   * @param {string} localDir - 本地目录
   * @param {boolean} preserveStructure - 是否保持目录结构
   * @param {boolean} verifyIntegrity - 是否验证完整性
   * @param {string} integrityAlgorithm - 完整性算法
   * @param {boolean} resume - 是否断点续传
   * @param {ProgressBar} progressBar - 进度条
   * @param {Object} result - 结果对象
   * @param {Function} onFileComplete - 文件完成回调
   * @returns {Promise<void>}
   * @private
   */
  async _downloadSingleFile(
    remoteFile, 
    localDir, 
    preserveStructure, 
    verifyIntegrity, 
    integrityAlgorithm, 
    resume,
    progressBar,
    result,
    onFileComplete
  ) {
    try {
      // 计算本地文件路径
      let localFile;
      if (preserveStructure) {
        // 保持相对路径结构
        const fileName = path.posix.basename(remoteFile);
        const remoteDir = path.posix.dirname(remoteFile);
        
        // 如果远程文件是绝对路径，去掉开头的斜杠
        const relativeRemotePath = remoteDir.startsWith('/') ? remoteDir.substring(1) : remoteDir;
        
        localFile = path.join(localDir, relativeRemotePath, fileName);
        
        // 确保本地目录存在
        const localFileDir = path.dirname(localFile);
        if (!fs.existsSync(localFileDir)) {
          fs.mkdirSync(localFileDir, { recursive: true });
        }
      } else {
        // 只使用文件名
        const fileName = path.posix.basename(remoteFile);
        localFile = path.join(localDir, fileName);
      }

      // 获取远程文件大小
      const stats = await this.sftpClient.getFileInfo(remoteFile);
      const fileSize = stats.size;

      // 下载文件
      await this.sftpClient.downloadFile(remoteFile, localFile, {
        verifyIntegrity,
        integrityAlgorithm,
        resume
      });

      // 更新结果
      result.downloaded.push({
        remote: remoteFile,
        local: localFile,
        size: fileSize
      });
      
      result.downloadedBytes += fileSize;

      // 更新进度条
      progressBar.update(result.downloadedBytes);

      // 调用文件完成回调
      if (onFileComplete) {
        onFileComplete({
          file: remoteFile,
          status: 'downloaded',
          size: fileSize
        });
      }
    } catch (error) {
      // 更新失败结果
      result.failed.push({
        file: remoteFile,
        error: error.message
      });
      
      Logger.error(`下载文件失败: ${remoteFile} - ${error.message}`);
    }
  }

  /**
   * 将数组分成指定大小的块
   * @param {Array} array - 数组
   * @param {number} size - 块大小
   * @returns {Array} - 分块后的数组
   * @private
   */
  _chunkArray(array, size) {
    const chunks = [];
    for (let i = 0; i < array.length; i += size) {
      chunks.push(array.slice(i, i + size));
    }
    return chunks;
  }
}

export default BatchTransfer;